using System;
using System.Collections.Generic;
using System.Text;

using MyAI.NeuralNetworkLib.Specification;
using MyAI.NeuralNetworkLib.Utils;

namespace MyAI.NeuralNetworkLib.Implementation
{
    public class SimpleNeuron : INeuron
    {
        #region Vars
        private List<double> _wights;
        private IActivationFunction _af;
        private double _offset = 0;        
        #endregion

        #region Counstructor
        public SimpleNeuron()
        {

        }
        #endregion

        #region StateCheck
        private void StateCheck()
        {
            if (_wights == null)
            {
                throw new InvalidOperationException("Reset firstly");
            }
        }
        #endregion

        #region INeuron Members

        public void Reset(int dimension, IActivationFunction activationFunction, List<double> afPrms, double offset)
        {
            _wights = new List<double>(dimension);
            Random r = new Random();
            for (int i = 0; i < dimension; i++)
            {
                _wights.Add(Randomizer.Instance.Nextdouble() - 0.5);
            }
            _af = activationFunction;
            _af.SetParams(afPrms);
            _offset = offset;
        }

        public double Activate(List<double> inputVector)
        {
            StateCheck();
            if (inputVector.Count != _wights.Count)
            {
                throw new ArgumentException("inputVector dimension is diffrent with neuron wights");
            }
            double net = _offset;
            for (int i = 0; i < inputVector.Count; i++)
            {
                net += _wights[i] * inputVector[i];
            }
            return _af.Calculate(net);
        }

        public List<double> Weights
        {
            set
            {
                StateCheck();
                if (value.Count != _wights.Count)
                {
                    throw new ArgumentException("value dimension is diffrent with neuron wights");
                }
                _wights = value;
            }
            get
            {
                StateCheck();
                return _wights;
            }
        }

        public double GetWeight(int n)
        {
            StateCheck();
            return _wights[n];
        }

        public void SetWeight(int n, double val)
        {
            StateCheck();
            if (n > _wights.Count || n < 0)
            {
                throw new ArgumentOutOfRangeException("n is out of range");
            }
            _wights[n] = val;
        }

        public double Offset
        {
            set
            {
                StateCheck();
                _offset = value;
            }
            get
            {
                StateCheck();
                return _offset;
            }
        }

        #endregion
    }
}
